<!DOCTYPE html>
<html>
  <head>
  <meta http-equiv="content-type" content="text/html; charset=utf-8">
  <meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" name="viewport">
  <meta name="description" content="tong.li&#39;s blog">
  <meta name="keyword" content="彤哥哥博客，95后技术爱好者,现就职于同程旅行/同程艺龙上海分公司，专注于互联网技术分享的平台。">
  
    <link rel="shortcut icon" href="/css/images/icon.png">
  
  <title>
    
      Redis持久化机制 | 彤哥哥的博客
    
  </title>
  <link href="https://cdn.staticfile.org/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet">
  <link href="https://cdn.staticfile.org/nprogress/0.2.0/nprogress.min.css" rel="stylesheet">
  <link href="https://cdn.staticfile.org/highlight.js/9.12.0/styles/tomorrow-night.min.css" rel="stylesheet">
  
<link rel="stylesheet" href="/css/style.css">

  
  <script src="https://cdn.staticfile.org/jquery/3.2.1/jquery.min.js"></script>
  <script src="https://cdn.staticfile.org/geopattern/1.2.3/js/geopattern.min.js"></script>
  <script src="https://cdn.staticfile.org/nprogress/0.2.0/nprogress.min.js"></script>
  
    
<script src="/js/qrious.js"></script>

  
  
  
  
    <!-- MathJax support START -->
    <script type="text/x-mathjax-config">
      MathJax.Hub.Config({
        tex2jax: {
          inlineMath: [ ['$','$'], ["\\(","\\)"]  ],
          processEscapes: true,
          skipTags: ['script', 'noscript', 'style', 'textarea', 'pre', 'code']
        }
      });
    </script>

    <script type="text/x-mathjax-config">
      MathJax.Hub.Queue(function() {
        var all = MathJax.Hub.getAllJax(), i;
        for (i=0; i < all.length; i += 1) {
          all[i].SourceElement().parentNode.className += ' has-jax';
        }
      });
    </script>
    <script type="text/javascript" src="https://cdn.staticfile.org/mathjax/2.7.5/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
    <!-- MathJax support END -->
  


  
  
    
<script src="/js/local-search.js"></script>


<meta name="generator" content="Hexo 5.4.2"></head>
<div class="wechat-share">
  <img src="/css/images/logo.png" />
</div>
  <body>
    <header class="header fixed-header">
  <div class="header-container">
    <a class="home-link" href="/">
      <div class="logo"></div>
      <span>彤哥哥的博客</span>
    </a>
    <ul class="right-list">
      
        <li class="list-item">
          
            <a href="/" class="item-link">主页</a>
          
        </li>
      
        <li class="list-item">
          
            <a href="/series/" class="item-link">分类</a>
          
        </li>
      
        <li class="list-item">
          
            <a href="/tags/" class="item-link">标签</a>
          
        </li>
      
        <li class="list-item">
          
            <a href="/archives/" class="item-link">归档</a>
          
        </li>
      
        <li class="list-item">
          
            <a href="/project/" class="item-link">项目</a>
          
        </li>
      
        <li class="list-item">
          
            <a href="/about/" class="item-link">关于</a>
          
        </li>
      
      
        <li class="menu-item menu-item-search right-list">
    <a role="button" class="popup-trigger">
        <i class="fa fa-search fa-fw"></i>
    </a>
</li>
      
    </ul>
    <div class="menu">
      <span class="icon-bar"></span>
      <span class="icon-bar"></span>
      <span class="icon-bar"></span>
    </div>
    <div class="menu-mask">
      <ul class="menu-list">
        
          <li class="menu-item">
            
              <a href="/" class="menu-link">主页</a>
            
          </li>
        
          <li class="menu-item">
            
              <a href="/series/" class="menu-link">分类</a>
            
          </li>
        
          <li class="menu-item">
            
              <a href="/tags/" class="menu-link">标签</a>
            
          </li>
        
          <li class="menu-item">
            
              <a href="/archives/" class="menu-link">归档</a>
            
          </li>
        
          <li class="menu-item">
            
              <a href="/project/" class="menu-link">项目</a>
            
          </li>
        
          <li class="menu-item">
            
              <a href="/about/" class="menu-link">关于</a>
            
          </li>
        
      </ul>
    </div>
    
      <div class="search-pop-overlay">
    <div class="popup search-popup">
        <div class="search-header">
            <span class="search-icon">
                <i class="fa fa-search"></i>
            </span>
            <div class="search-input-container">
                <input autocomplete="off" autocapitalize="off"
                    placeholder="Please enter your keyword(s) to search." spellcheck="false"
                    type="search" class="search-input">
            </div>
            <span class="popup-btn-close">
                <i class="fa fa-times-circle"></i>
            </span>
        </div>
        <div id="search-result">
            <div id="no-result">
                <i class="fa fa-spinner fa-pulse fa-5x fa-fw"></i>
            </div>
        </div>
    </div>
</div>
    
  </div>
</header>

    <div id="article-banner">
  <h2>Redis持久化机制</h2>
  <p class="post-date">2020-04-17</p>
  <div class="arrow-down">
    <a href="javascript:;"></a>
  </div>
</div>
<main class="app-body flex-box">
  <!-- Article START -->
  <article class="post-article">
    <section class="markdown-content"><h1 id="1-Redis持久化"><a href="#1-Redis持久化" class="headerlink" title="1. Redis持久化"></a>1. Redis持久化</h1><p>Redis作为内存数据库，极大的提高了数据的读写效率，这一点毋庸置疑。但是内存作为一个易失存储器，所有的数据在断电后就会丢失，这些在我们看来是不能够接受的。</p>
<p>为了解决以上问题，Redis为我们提供了不同的持久性选项范围：</p>
<ul>
<li>RDB持久性按指定的时间间隔执行数据集的时间点快照。</li>
<li>AOF持久性会记录服务器接收的每个写入操作，这些操作将在服务器启动时再次播放，以重建原始数据集。使用与Redis协议本身相同的格式记录命令，并且仅采用追加方式。当日志太大时，Redis可以在后台重写日志。</li>
<li>如果希望，只要您的数据在服务器运行时就一直存在，则可以完全禁用持久性。</li>
<li>可以在同一实例中同时合并AOF和RDB。请注意，在这种情况下，当Redis重新启动时，AOF文件将用于重建原始数据集，因为它可以保证是最完整的。</li>
</ul>
<h2 id="1-1-RDB持久化"><a href="#1-1-RDB持久化" class="headerlink" title="1.1 RDB持久化"></a>1.1 RDB持久化</h2><h3 id="1-1-1-RDB简述"><a href="#1-1-1-RDB简述" class="headerlink" title="1.1.1 RDB简述"></a>1.1.1 RDB简述</h3><p>Redis默认的持久化是RDB方式，RDB又名持久化快照，该功能可以创建出一个经过压缩的二进制文件(dump.rdb)。</p>
<p>当 Redis 需要做持久化时，Redis 会 fork 一个子进程，子进程将数据写到磁盘上一个临时 RDB 文件中。</p>
<p>当子进程完成写临时文件后，将原来的 RDB 替换掉，这样的好处是可以 copy-on-write。</p>
<h3 id="1-1-2-创建RDB文件的三种方式"><a href="#1-1-2-创建RDB文件的三种方式" class="headerlink" title="1.1.2 创建RDB文件的三种方式"></a>1.1.2 创建RDB文件的三种方式</h3><ul>
<li><p>通过SAVE命令创建RDB文件</p>
<ul>
<li>通过执行SAVE命令以同步方式创建出当前Redis服务器所有数据库数据的RDB文件。</li>
<li>在SAVE命令执行期间,Redis服务将阻塞客户端服务,直到创建完成后恢复服务。</li>
<li>若已经有相应的RDB文件,执行SAVE后,移除旧文件,保留新文件。</li>
<li>复杂度：O(N)，其中N为Redis服务器所有数据库包含的键值对总数量。</li>
</ul>
</li>
<li><p>通过BGSAVE命令创建RDB文件</p>
<ul>
<li>异步创建RDB文件,不会直接通过Redis服务进程创建,而是fork子进程创建,不阻塞客户端服务,</li>
<li>当执行BGSAVE命令后,创建一个子进程,子进程执行SAVE命令,创建最新的RDB快照,创建完毕后,子进程退出并通知父进程替换为最新的RDB快照。</li>
<li>执行BGSAVE后,父进程占用的内存数量越大,创建子进程耗费的时间越长,仍然可能会有短暂地阻塞。</li>
<li>复杂度：O(N)，其中N为Redis服务器所有数据库包含的键值对总数量。</li>
<li>离线Redis服务器用SAVE保存快照效率高于BGSAVE。</li>
</ul>
</li>
<li><p>通过配置选项自动创建RDB文件</p>
<p>我们打开redis.conf找到SNAPSHOTTING 位置,我们可以详细的看出RDB快照配置说明</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">################################ SNAPSHOTTING  ################################</span></span><br><span class="line"><span class="comment">#</span></span><br><span class="line"><span class="comment"># Save the DB on disk: 保存DB到磁盘</span></span><br><span class="line"><span class="comment">#</span></span><br><span class="line"><span class="comment">#   save &lt;seconds&gt; &lt;changes&gt;  参数选项: save  秒数 秒数之内key的changes数量</span></span><br><span class="line"><span class="comment">#</span></span><br><span class="line"><span class="comment">#   Will save the DB if both the given number of seconds and the given</span></span><br><span class="line"><span class="comment">#   number of write operations against the DB occurred. 若数据库达到seconds和changes数时,保存一次快照文件</span></span><br><span class="line"><span class="comment">#</span></span><br><span class="line"><span class="comment">#   In the example below the behaviour will be to save: </span></span><br><span class="line"><span class="comment">#   after 900 sec (15 min) if at least 1 key changed </span></span><br><span class="line"><span class="comment">#   after 300 sec (5 min) if at least 10 keys changed</span></span><br><span class="line"><span class="comment">#   after 60 sec if at least 10000 keys changed</span></span><br><span class="line"><span class="comment">#</span></span><br><span class="line"><span class="comment">#   Note: you can disable saving completely by commenting out all &quot;save&quot; lines.</span></span><br><span class="line"><span class="comment">#</span></span><br><span class="line"><span class="comment">#   It is also possible to remove all the previously configured save</span></span><br><span class="line"><span class="comment">#   points by adding a save directive with a single empty string argument</span></span><br><span class="line"><span class="comment">#   like in the following example:</span></span><br><span class="line"><span class="comment">#</span></span><br><span class="line"><span class="comment">#   save &quot;&quot;  # 通过配置空串关闭RDB模式</span></span><br><span class="line"></span><br><span class="line">save 900 1 <span class="comment"># 默认900秒(15分钟)之内至少有1个key被changed触发快照保存</span></span><br><span class="line">save 300 10 <span class="comment"># 默认900秒(5分钟)之内至少有10个key被changed触发快照保存</span></span><br><span class="line">save 60 10000 <span class="comment"># 默认900秒(1分钟)之内至少有100000个key被changed触发快照保存</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># By default Redis will stop accepting writes if RDB snapshots are enabled</span></span><br><span class="line"><span class="comment"># (at least one save point) and the latest background save failed.</span></span><br><span class="line"><span class="comment"># This will make the user aware (in a hard way) that data is not persisting</span></span><br><span class="line"><span class="comment"># on disk properly, otherwise chances are that no one will notice and some</span></span><br><span class="line"><span class="comment"># disaster will happen.</span></span><br><span class="line"><span class="comment">#</span></span><br><span class="line"><span class="comment"># If the background saving process will start working again Redis will</span></span><br><span class="line"><span class="comment"># automatically allow writes again.</span></span><br><span class="line"><span class="comment">#</span></span><br><span class="line"><span class="comment"># However if you have setup your proper monitoring of the Redis server</span></span><br><span class="line"><span class="comment"># and persistence, you may want to disable this feature so that Redis will</span></span><br><span class="line"><span class="comment"># continue to work as usual even if there are problems with disk,</span></span><br><span class="line"><span class="comment"># permissions, and so forth.</span></span><br><span class="line">stop-writes-on-bgsave-error <span class="built_in">yes</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># Compress string objects using LZF when dump .rdb databases?</span></span><br><span class="line"><span class="comment"># For default that&#x27;s set to &#x27;yes&#x27; as it&#x27;s almost always a win.</span></span><br><span class="line"><span class="comment"># If you want to save some CPU in the saving child set it to &#x27;no&#x27; but</span></span><br><span class="line"><span class="comment"># the dataset will likely be bigger if you have compressible values or keys.</span></span><br><span class="line">rdbcompression <span class="built_in">yes</span> RDB文件压缩</span><br><span class="line"></span><br><span class="line"><span class="comment"># Since version 5 of RDB a CRC64 checksum is placed at the end of the file.</span></span><br><span class="line"><span class="comment"># This makes the format more resistant to corruption but there is a performance</span></span><br><span class="line"><span class="comment"># hit to pay (around 10%) when saving and loading RDB files, so you can disable it</span></span><br><span class="line"><span class="comment"># for maximum performances.</span></span><br><span class="line"><span class="comment">#</span></span><br><span class="line"><span class="comment"># RDB files created with checksum disabled have a checksum of zero that will</span></span><br><span class="line"><span class="comment"># tell the loading code to skip the check.</span></span><br><span class="line">rdbchecksum <span class="built_in">yes</span> 是否校验RDB的完整性</span><br><span class="line"></span><br><span class="line"><span class="comment"># The filename where to dump the DB  RDB存储的文件名称</span></span><br><span class="line">dbfilename dump.rdb  </span><br><span class="line"></span><br><span class="line"><span class="comment"># The working directory.</span></span><br><span class="line"><span class="comment">#</span></span><br><span class="line"><span class="comment"># The DB will be written inside this directory, with the filename specified</span></span><br><span class="line"><span class="comment"># above using the &#x27;dbfilename&#x27; configuration directive.</span></span><br><span class="line"><span class="comment">#</span></span><br><span class="line"><span class="comment"># The Append Only File will also be created inside this directory.</span></span><br><span class="line"><span class="comment">#</span></span><br><span class="line"><span class="comment"># Note that you must specify a directory here, not a file name.</span></span><br><span class="line"><span class="built_in">dir</span> ./  RDB的存储工作目录</span><br></pre></td></tr></table></figure></li>
</ul>
<h3 id="1-1-3-RDB文件结构"><a href="#1-1-3-RDB文件结构" class="headerlink" title="1.1.3 RDB文件结构"></a>1.1.3 RDB文件结构</h3><p>我们打开dump.rdb文件,我们可以分析一下RDB文件的组成结构:</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">REDIS0009ъ	redis-ver5.0.8ъ</span><br><span class="line">redis-bitsј@ъctime¬«ѓС^ъused-mem¬јa(</span><br></pre></td></tr></table></figure>

<ul>
<li><p>RDB文件标识符</p>
<p>​       RDB文件标识符文件最开头的部分为RDB文件标识符，这个标识符的内容为”REDIS”这5个字符。Redis服务器在尝试载入RDB文件的时候，可以通过这个标识符快速地判断该文件是否为真正的RDB文件。</p>
</li>
<li><p>版本号</p>
<p>​      跟在RDB文件标识符之后的是RDB文件的版本号，这个版本号是一个字符串格式的数字，长度为4个字符。</p>
<p>目前最新的RDB文件版本为第9版，因此RDB文件的版本号将为字符串”0009”。</p>
<p>​      不同版本的RDB文件在结构上都会有一些不同，总的来说，新版RDB文件都会在旧版RDB文件的基础上添加更多信息，因此RDB文件的版本越新，RDB文件的结构就越复杂。关于RDB文件，需要说明的另外一点是新版Redis服务器总是能够向下兼容旧版Redis服务器生成的RDB文件。</p>
<p>​      比如，生成第9版RDB文件的Redis 5.0既能够正常读入由Redis 4.0生成的第8版RDB文件，也能够读入由Redis 3.2生成的第7版RDB文件，甚至更旧版本的RDB文件也是可以的。</p>
<p>​      与此相反，如果Redis服务器生成的是较旧版本的RDB文件，那么它是无法读入更新版本的RDB文件的。比如，生成第8版RDB文件的Redis 4.0就不能读入由Redis 5.0生成的第9版RDB文件。</p>
</li>
<li><p>设备附加信息</p>
<p>​      RDB文件的设备附加信息部分记录了生成RDB文件的Redis服务器及其所在平台的信息，比如服务器的版本号、宿主机器的架构、创建RDB文件时的时间戳、服务器占用的内存数量等。</p>
</li>
<li><p>数据库数据</p>
<p>​       RDB文件的数据库数据部分记录了Redis服务器存储的0个或任意多个数据库的数据，当这个部分包含多数个数据库的数据时，各个数据库的数据将按照数据库号码从小到大进行排列，比如，0号数据库的数据将排在最前面，紧接着是1号数据库的数据，然后是2号数据库的数据，以此类推。</p>
<p>​      每个数据库都由数据库号码、键值对总数量、带有过期时间的键值对数量、键值对数据部分。</p>
</li>
<li><p>Lua脚本缓存</p>
<p>​       如果Redis服务器启用了复制功能，那么服务器将在RDB文件的Lua脚本缓存部分保存所有已被缓存的Lua脚本。这样一来，从服务器在载入RDB文件完成数据同步之后，就可以继续执行主服务器发来的EVALSHA命令了。</p>
</li>
<li><p>EOF</p>
<p>​        RDB文件的EOF部分用于标识RDB正文内容的末尾，它的实际值为二进制值0xFF。当Redis服务器读取到EOF的时候，它知道RDB文件的正文部分已经全部读取完毕了。</p>
</li>
<li><p>CRC64校验和</p>
<p>​       RDB文件的末尾是一个以无符号64位整数表示的CRC64校验和，比如5097628732947693614。Redis服务器在读入RDB文件时会通过这个校验和来快速地检查RDB文件是否有出错或者损坏的情况出现。</p>
</li>
</ul>
<h3 id="1-1-4-RDB文件载入恢复"><a href="#1-1-4-RDB文件载入恢复" class="headerlink" title="1.1.4 RDB文件载入恢复"></a>1.1.4 RDB文件载入恢复</h3><ul>
<li>当Redis服务器启动时，它会在工作目录中查找是否有RDB文件出现，如果有就打开它，然后读取文件的内容并执行载入操作。</li>
<li>检查文件开头的标识符是否为”REDIS”，如果是则继续执行后续的载入操作，不是则抛出错误并终止载入操作。</li>
<li>检查文件的RDB版本号，以此来判断当前Redis服务器能否读取这一版本的RDB文件。</li>
<li>根据文件中记录的设备附加信息，执行相应的操作和设置。</li>
<li>检查文件的数据库数据部分是否为空，如果不为空就执行以下子操作：<ul>
<li>根据文件记录的数据库号码，切换至正确的数据库。</li>
<li>根据文件记录的键值对总数量以及带有过期时间的键值对数量，设置数据库底层数据结构。</li>
<li>一个接一个地载入文件记录的所有键值对数据，并在数据库中重建这些键值对。</li>
</ul>
</li>
<li>如果服务器启用了复制功能，那么将之前缓存的Lua脚本重新载入缓存中。</li>
<li>遇到EOF标识，确认RDB正文已经全部读取完毕。</li>
<li>载入RDB文件末尾记录的CRC64校验和，把它与载入数据期间计算出的CRC64校验和进行对比，以此来判断被载入的数据是否完好无损。</li>
<li>RDB文件载入完毕，服务器开始接受客户端请求。</li>
</ul>
<h3 id="1-1-5-RDB持久化优缺点"><a href="#1-1-5-RDB持久化优缺点" class="headerlink" title="1.1.5 RDB持久化优缺点"></a>1.1.5 RDB持久化优缺点</h3><p>优点：</p>
<ul>
<li>RDB非常适合做冷备，可以将这种完整的数据文件发送到一些远程的安全存储上去，比如云服务器。</li>
<li>RDB对redis对外提供的读写服务，影响非常小，可以让redis保持高性能，因为redis主进程只需要fork一个子进程，让子进程执行磁盘IO操作来进行RDB持久化即可</li>
<li>相对于AOF持久化机制来说，直接基于RDB数据文件来重启和恢复redis进程，更加快速。</li>
</ul>
<p>缺点：</p>
<ul>
<li>如果想要在redis故障时，尽可能少的丢失数据，那么RDB没有AOF好。因为SAVE命令是一个同步操作，它的开始和结束都位于同一个原子时间之内，所以如果用户使用SAVE命令进行持久化，那么服务器在停机时将丢失最后一次成功执行SAVE命令之后产生的所有数据。无论用户使用的是SAVE命令还是BGSAVE命令，停机时服务器丢失的数据量将取决于创建RDB文件的时间间隔：间隔越长，停机时丢失的数据也就越多。</li>
<li>RDB每次在fork子进程来执行RDB快照数据文件生成的时候，如果数据文件特别大，Fork子进程可能很耗时，可能会导致对客户端提供的服务暂停数毫秒，或者甚至数秒。</li>
</ul>
<h2 id="1-2-AOF持久化"><a href="#1-2-AOF持久化" class="headerlink" title="1.2 AOF持久化"></a>1.2 AOF持久化</h2><h3 id="1-2-1-AOF简述"><a href="#1-2-1-AOF简述" class="headerlink" title="1.2.1 AOF简述"></a>1.2.1 AOF简述</h3><p>与全量式的RDB持久化功能不同，AOF提供的是增量式的持久化功能，这种持久化的核心原理在于：</p>
<p>服务器每次执行完写命令之后，都会以协议文本的方式将被执行的命令追加到AOF文件的末尾。这样一来，服务器在停机之后，只要重新执行AOF文件中保存的Redis命令，就可以将数据库恢复至停机之前的状态。</p>
<h3 id="1-2-2-AOF配置"><a href="#1-2-2-AOF配置" class="headerlink" title="1.2.2 AOF配置"></a>1.2.2 AOF配置</h3><p>我们在redis.conf配置文件可以找出APPEND ONLY MODE配置项：</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">############################## APPEND ONLY MODE ###############################</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># By default Redis asynchronously dumps the dataset on disk. This mode is</span></span><br><span class="line"><span class="comment"># good enough in many applications, but an issue with the Redis process or</span></span><br><span class="line"><span class="comment"># a power outage may result into a few minutes of writes lost (depending on</span></span><br><span class="line"><span class="comment"># the configured save points).</span></span><br><span class="line"><span class="comment">#</span></span><br><span class="line"><span class="comment"># The Append Only File is an alternative persistence mode that provides</span></span><br><span class="line"><span class="comment"># much better durability. For instance using the default data fsync policy</span></span><br><span class="line"><span class="comment"># (see later in the config file) Redis can lose just one second of writes in a</span></span><br><span class="line"><span class="comment"># dramatic event like a server power outage, or a single write if something</span></span><br><span class="line"><span class="comment"># wrong with the Redis process itself happens, but the operating system is</span></span><br><span class="line"><span class="comment"># still running correctly.</span></span><br><span class="line"><span class="comment">#</span></span><br><span class="line"><span class="comment"># AOF and RDB persistence can be enabled at the same time without problems.</span></span><br><span class="line"><span class="comment"># If the AOF is enabled on startup Redis will load the AOF, that is the file</span></span><br><span class="line"><span class="comment"># with the better durability guarantees.</span></span><br><span class="line"><span class="comment">#</span></span><br><span class="line"><span class="comment"># Please check http://redis.io/topics/persistence for more information.</span></span><br><span class="line"></span><br><span class="line">appendonly no <span class="comment"># no为不开启AOF持久化，yes为开启AOF，默认不开启</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># The name of the append only file (default: &quot;appendonly.aof&quot;)</span></span><br><span class="line"></span><br><span class="line">appendfilename <span class="string">&quot;appendonly.aof&quot;</span>  <span class="comment"># AOF持久化文件</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># The fsync() call tells the Operating System to actually write data on disk</span></span><br><span class="line"><span class="comment"># instead of waiting for more data in the output buffer. Some OS will really flush</span></span><br><span class="line"><span class="comment"># data on disk, some other OS will just try to do it ASAP.</span></span><br><span class="line"><span class="comment">#</span></span><br><span class="line"><span class="comment"># Redis supports three different modes:</span></span><br><span class="line"><span class="comment">#</span></span><br><span class="line"><span class="comment"># no: don&#x27;t fsync, just let the OS flush the data when it wants. Faster. 不fsyn，更快</span></span><br><span class="line"><span class="comment"># always: fsync after every write to the append only log. Slow, Safest. 每次fsync，慢点但是最安全</span></span><br><span class="line"><span class="comment"># everysec: fsync only one time every second. Compromise.  每秒每次fsync，折中</span></span><br><span class="line"><span class="comment">#</span></span><br><span class="line"><span class="comment"># The default is &quot;everysec&quot;, as that&#x27;s usually the right compromise between</span></span><br><span class="line"><span class="comment"># speed and data safety. It&#x27;s up to you to understand if you can relax this to</span></span><br><span class="line"><span class="comment"># &quot;no&quot; that will let the operating system flush the output buffer when</span></span><br><span class="line"><span class="comment"># it wants, for better performances (but if you can live with the idea of</span></span><br><span class="line"><span class="comment"># some data loss consider the default persistence mode that&#x27;s snapshotting),</span></span><br><span class="line"><span class="comment"># or on the contrary, use &quot;always&quot; that&#x27;s very slow but a bit safer than</span></span><br><span class="line"><span class="comment"># everysec. </span></span><br><span class="line"><span class="comment">#</span></span><br><span class="line"><span class="comment"># More details please check the following article:</span></span><br><span class="line"><span class="comment"># http://antirez.com/post/redis-persistence-demystified.html</span></span><br><span class="line"><span class="comment">#</span></span><br><span class="line"><span class="comment"># If unsure, use &quot;everysec&quot;.</span></span><br><span class="line"><span class="comment"># 设置AOF文件的冲洗频率，一般不会直接把数据write磁盘里，而是先写入入buffer里，等待时机最后flush到磁盘</span></span><br><span class="line"><span class="comment"># appendfsync always # 每执行一个写命令，就对AOF文件执行一次冲洗操作，最多丢失一个命令，性能极慢，安全性极高</span></span><br><span class="line">appendfsync everysec <span class="comment"># 每隔1秒，就对AOF文件执行一次冲洗操作，最多丢失1秒之内产生的命令，安全性和性能折中</span></span><br><span class="line"><span class="comment"># appendfsync no # 不主动对AOF文件执行冲洗操作，由操作系统决定何时对AOF进行冲洗，性能最快，安全性最低</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># When the AOF fsync policy is set to always or everysec, and a background</span></span><br><span class="line"><span class="comment"># saving process (a background save or AOF log background rewriting) is</span></span><br><span class="line"><span class="comment"># performing a lot of I/O against the disk, in some Linux configurations</span></span><br><span class="line"><span class="comment"># Redis may block too long on the fsync() call. Note that there is no fix for</span></span><br><span class="line"><span class="comment"># this currently, as even performing fsync in a different thread will block</span></span><br><span class="line"><span class="comment"># our synchronous write(2) call.</span></span><br><span class="line"><span class="comment">#</span></span><br><span class="line"><span class="comment"># In order to mitigate this problem it&#x27;s possible to use the following option</span></span><br><span class="line"><span class="comment"># that will prevent fsync() from being called in the main process while a</span></span><br><span class="line"><span class="comment"># BGSAVE or BGREWRITEAOF is in progress.</span></span><br><span class="line"><span class="comment">#</span></span><br><span class="line"><span class="comment"># This means that while another child is saving, the durability of Redis is</span></span><br><span class="line"><span class="comment"># the same as &quot;appendfsync none&quot;. In practical terms, this means that it is</span></span><br><span class="line"><span class="comment"># possible to lose up to 30 seconds of log in the worst scenario (with the</span></span><br><span class="line"><span class="comment"># default Linux settings).</span></span><br><span class="line"><span class="comment">#</span></span><br><span class="line"><span class="comment"># If you have latency problems turn this to &quot;yes&quot;. Otherwise leave it as</span></span><br><span class="line"><span class="comment"># &quot;no&quot; that is the safest pick from the point of view of durability.</span></span><br><span class="line"></span><br><span class="line">no-appendfsync-on-rewrite no <span class="comment"># 最安全但会阻塞，设置为yes，则和appendfsync no类似</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># Automatic rewrite of the append only file.</span></span><br><span class="line"><span class="comment"># Redis is able to automatically rewrite the log file implicitly calling</span></span><br><span class="line"><span class="comment"># BGREWRITEAOF when the AOF log size grows by the specified percentage.</span></span><br><span class="line"><span class="comment">#</span></span><br><span class="line"><span class="comment"># This is how it works: Redis remembers the size of the AOF file after the</span></span><br><span class="line"><span class="comment"># latest rewrite (if no rewrite has happened since the restart, the size of</span></span><br><span class="line"><span class="comment"># the AOF at startup is used).</span></span><br><span class="line"><span class="comment">#</span></span><br><span class="line"><span class="comment"># This base size is compared to the current size. If the current size is</span></span><br><span class="line"><span class="comment"># bigger than the specified percentage, the rewrite is triggered. Also</span></span><br><span class="line"><span class="comment"># you need to specify a minimal size for the AOF file to be rewritten, this</span></span><br><span class="line"><span class="comment"># is useful to avoid rewriting the AOF file even if the percentage increase</span></span><br><span class="line"><span class="comment"># is reached but it is still pretty small.</span></span><br><span class="line"><span class="comment">#</span></span><br><span class="line"><span class="comment"># Specify a percentage of zero in order to disable the automatic AOF</span></span><br><span class="line"><span class="comment"># rewrite feature.</span></span><br><span class="line"></span><br><span class="line">auto-aof-rewrite-percentage 100 <span class="comment"># 控制触发自动AOF文件重写所需文件体积增大的比例</span></span><br><span class="line">auto-aof-rewrite-min-size 64mb  <span class="comment"># 自动AOF重写所需要的最小文件体积</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># An AOF file may be found to be truncated at the end during the Redis</span></span><br><span class="line"><span class="comment"># startup process, when the AOF data gets loaded back into memory.</span></span><br><span class="line"><span class="comment"># This may happen when the system where Redis is running</span></span><br><span class="line"><span class="comment"># crashes, especially when an ext4 filesystem is mounted without the</span></span><br><span class="line"><span class="comment"># data=ordered option (however this can&#x27;t happen when Redis itself</span></span><br><span class="line"><span class="comment"># crashes or aborts but the operating system still works correctly).</span></span><br><span class="line"><span class="comment">#</span></span><br><span class="line"><span class="comment"># Redis can either exit with an error when this happens, or load as much</span></span><br><span class="line"><span class="comment"># data as possible (the default now) and start if the AOF file is found</span></span><br><span class="line"><span class="comment"># to be truncated at the end. The following option controls this behavior.</span></span><br><span class="line"><span class="comment">#</span></span><br><span class="line"><span class="comment"># If aof-load-truncated is set to yes, a truncated AOF file is loaded and</span></span><br><span class="line"><span class="comment"># the Redis server starts emitting a log to inform the user of the event.</span></span><br><span class="line"><span class="comment"># Otherwise if the option is set to no, the server aborts with an error</span></span><br><span class="line"><span class="comment"># and refuses to start. When the option is set to no, the user requires</span></span><br><span class="line"><span class="comment"># to fix the AOF file using the &quot;redis-check-aof&quot; utility before to restart</span></span><br><span class="line"><span class="comment"># the server.</span></span><br><span class="line"><span class="comment">#</span></span><br><span class="line"><span class="comment"># Note that if the AOF file will be found to be corrupted in the middle</span></span><br><span class="line"><span class="comment"># the server will still exit with an error. This option only applies when</span></span><br><span class="line"><span class="comment"># Redis will try to read more data from the AOF file but not enough bytes</span></span><br><span class="line"><span class="comment"># will be found.</span></span><br><span class="line">aof-load-truncated <span class="built_in">yes</span> <span class="comment"># 加载aof时如果有错如何处理</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># When rewriting the AOF file, Redis is able to use an RDB preamble in the</span></span><br><span class="line"><span class="comment"># AOF file for faster rewrites and recoveries. When this option is turned</span></span><br><span class="line"><span class="comment"># on the rewritten AOF file is composed of two different stanzas:</span></span><br><span class="line"><span class="comment">#</span></span><br><span class="line"><span class="comment">#   [RDB file][AOF tail]</span></span><br><span class="line"><span class="comment">#</span></span><br><span class="line"><span class="comment"># When loading Redis recognizes that the AOF file starts with the &quot;REDIS&quot;</span></span><br><span class="line"><span class="comment"># string and loads the prefixed RDB file, and continues loading the AOF</span></span><br><span class="line"><span class="comment"># tail.</span></span><br><span class="line">aof-use-rdb-preamble <span class="built_in">yes</span>   <span class="comment"># RDB-AOF混合持久化</span></span><br></pre></td></tr></table></figure>



<h3 id="1-2-3-AOF持久化优缺点"><a href="#1-2-3-AOF持久化优缺点" class="headerlink" title="1.2.3 AOF持久化优缺点"></a>1.2.3 AOF持久化优缺点</h3><p>优点：</p>
<ul>
<li>与RDB持久化可能会丢失大量数据相比，AOF持久化的安全性要高得多：通过使用everysec选项，用户可以将数据丢失的时间窗口限制在1s之内。</li>
<li>AOF日志文件以append-only模式写入，所以没有任何磁盘寻址的开销，写入性能非常高，而且文件不容易破损，即使文件尾部破损，也很容易修复。</li>
<li>AOF日志文件即使过大的时候，出现后台重写操作，也不回影响客户端的读写。因为再rewrite log的时候，会对其中的指令进行压缩，创建一份需要恢复数据的最小日志出来。再创建新日志文件的时候，老的日志文件还是照常写入。当新的merge后的日志文件ready的时候，再交换老日志文件即可。</li>
<li>AOF日志文件的命令通过非常可读的方式进行记录，这个特性非常适合做灾难性的误删除的紧急恢复。比如不小心使用flushall命令清空了所有数据，只要这个时候后台rewrite还没有发生，那么就可以立即拷贝AOF文件，将最后一条flushall命令给删除，然后再将AOF文件放回去，就可以通过恢复机制，自动恢复所有数据。</li>
</ul>
<p>缺点：</p>
<ul>
<li>AOF文件存储的是协议文本，所以它的体积会比包含相同数据、二进制格式的RDB文件要大得多，并且生成AOF文件所需的时间也会比生成RDB文件所需的时间更长。</li>
<li>因为RDB持久化可以直接通过RDB文件恢复数据库数据，而AOF持久化则需要通过执行AOF文件中保存的命令来恢复数据库（前者是直接的数据恢复操作，而后者则是间接的数据恢复操作），所以RDB持久化的数据恢复速度将比AOF持久化的数据恢复速度快得多，并且数据库体积越大，这两者之间的差距就会越明显。</li>
<li>因为AOF重写使用的BGREWRITEAOF命令与RDB持久化使用的BGSAVE命令一样都需要创建子进程，所以在数据库体积较大的情况下，进行AOF文件重写将占用大量资源，并导致服务器被短暂地阻塞。</li>
</ul>
<h2 id="1-3-RDB-AOF混合持久化"><a href="#1-3-RDB-AOF混合持久化" class="headerlink" title="1.3 RDB-AOF混合持久化"></a>1.3 RDB-AOF混合持久化</h2><h3 id="1-3-1-RDB-AOF混合持久化简述"><a href="#1-3-1-RDB-AOF混合持久化简述" class="headerlink" title="1.3.1 RDB-AOF混合持久化简述"></a>1.3.1 RDB-AOF混合持久化简述</h3><p>Redis从4.0版本开始引入RDB-AOF混合持久化模式，这种模式是基于AOF持久化模式构建而来的。</p>
<p>如果用户打开了服务器的AOF持久化功能,并且将aof-use-rdb-preamble选项的值设置成了yes，那么Redis服务器在执行AOF重写操作时，就会像执行BGSAVE命令那样，根据数据库当前的状态生成出相应的RDB数据，并将这些数据写入新建的AOF文件中，至于那些在AOF重写开始之后执行的Redis命令，则会继续以协议文本的方式追加到新AOF文件的末尾，即已有的RDB数据的后面。</p>
<p>换句话说，在开启了RDB-AOF混合持久化功能之后，服务器生成的AOF文件将由两个部分组成，其中位于AOF文件开头的是RDB格式的数据，而跟在RDB数据后面的则是AOF格式的数据。</p>
<h3 id="1-3-2-RDB和AOF同时开启问题"><a href="#1-3-2-RDB和AOF同时开启问题" class="headerlink" title="1.3.2 RDB和AOF同时开启问题"></a>1.3.2 RDB和AOF同时开启问题</h3><p>如果用户使用的是Redis 4.0之前的版本，那么同时使用RDB持久化和AOF持久化仍然是可行的，只要注意以下问题即可：</p>
<ul>
<li>同时使用两种持久化功能需要耗费大量系统资源，系统的硬件必须能够支撑运行这两种功能所需的资源消耗，否则会给系统性能带来影响。</li>
<li>Redis服务器在启动时，会优先使用AOF文件进行数据恢复，只有在没有检测到AOF文件时，才会考虑寻找并使用RDB文件进行数据恢复。</li>
<li>当Redis服务器正在后台生成新的RDB文件时，如果有用户向服务器发送BGREWRITEAOF命令，或者配置选项中设置的AOF重写条件被满足了，那么服务器将把AOF重写操作推延到RDB文件创建完毕之后再执行，以此来避免两种持久化操作同时执行并争抢系统资源。</li>
<li>同样，当服务器正在执行BGREWRITEAOF命令时，用户发送或者被触发的BGSAVE命令也会推延到BGREWRITEAOF命令执行完毕之后再执行。</li>
</ul>
<h1 id="2-参考资料"><a href="#2-参考资料" class="headerlink" title="2. 参考资料"></a>2. 参考资料</h1><ul>
<li><a target="_blank" rel="noopener" href="https://redis.io/topics/persistence">Redis官网-持久化文档</a></li>
<li><a target="_blank" rel="noopener" href="http://oldblog.antirez.com/post/redis-persistence-demystified.html">神秘的Redis持久化</a></li>
<li><a target="_blank" rel="noopener" href="https://book.douban.com/subject/25900156/">Redis设计与实现-黄建宏著</a></li>
</ul>
</section>
    <!-- Tags START -->
    
      <div class="tags">
        <span>Tags:</span>
        
  <a href="/tags#Redis" >
    <span class="tag-code">Redis</span>
  </a>

      </div>
    
    <!-- Tags END -->
    <!-- NAV START -->
    
  <div class="nav-container">
    <!-- reverse left and right to put prev and next in a more logic postition -->
    
      <a class="nav-left" href="/2020/04/01/%E4%BA%86%E8%A7%A3%E5%B8%B8%E8%A7%81%E7%9A%84Redis%E9%9B%86%E7%BE%A4%E6%96%B9%E5%BC%8F/">
        <span class="nav-arrow">← </span>
        
          了解常见的Redis集群方式
        
      </a>
    
    
      <a class="nav-right" href="/2020/05/18/%E6%B7%B1%E5%85%A5%E5%88%86%E6%9E%90ArrayList%E6%BA%90%E7%A0%81/">
        
          深入分析ArrayList源码
        
        <span class="nav-arrow"> →</span>
      </a>
    
  </div>

    <!-- NAV END -->
    <!-- 打赏 START -->
    
      <div class="money-like">
        <div class="reward-btn">
          赏
          <span class="money-code">
            <span class="alipay-code">
              <div class="code-image"></div>
              <b>使用支付宝打赏</b>
            </span>
            <span class="wechat-code">
              <div class="code-image"></div>
              <b>使用微信打赏</b>
            </span>
          </span>
        </div>
        <p class="notice">若你觉得我的文章对你有帮助，欢迎点击上方按钮对我打赏</p>
      </div>
    
    <!-- 打赏 END -->
    <!-- 二维码 START -->
    
      <div class="qrcode">
        <canvas id="share-qrcode"></canvas>
        <p class="notice">扫描二维码，分享此文章</p>
      </div>
    
    <!-- 二维码 END -->
    
      <!-- Utterances START -->
      <div id="utterances"></div>
      <script src="https://utteranc.es/client.js"
        repo="ltyeamin/blogtalks"
        issue-term="pathname"
        theme="github-light"
        crossorigin="anonymous"
        async></script>    
      <!-- Utterances END -->
    
  </article>
  <!-- Article END -->
  <!-- Catalog START -->
  
    <aside class="catalog-container">
  <div class="toc-main">
    <strong class="toc-title">Catalog</strong>
    
      <ol class="toc-nav"><li class="toc-nav-item toc-nav-level-1"><a class="toc-nav-link" href="#1-Redis%E6%8C%81%E4%B9%85%E5%8C%96"><span class="toc-nav-text">1. Redis持久化</span></a><ol class="toc-nav-child"><li class="toc-nav-item toc-nav-level-2"><a class="toc-nav-link" href="#1-1-RDB%E6%8C%81%E4%B9%85%E5%8C%96"><span class="toc-nav-text">1.1 RDB持久化</span></a><ol class="toc-nav-child"><li class="toc-nav-item toc-nav-level-3"><a class="toc-nav-link" href="#1-1-1-RDB%E7%AE%80%E8%BF%B0"><span class="toc-nav-text">1.1.1 RDB简述</span></a></li><li class="toc-nav-item toc-nav-level-3"><a class="toc-nav-link" href="#1-1-2-%E5%88%9B%E5%BB%BARDB%E6%96%87%E4%BB%B6%E7%9A%84%E4%B8%89%E7%A7%8D%E6%96%B9%E5%BC%8F"><span class="toc-nav-text">1.1.2 创建RDB文件的三种方式</span></a></li><li class="toc-nav-item toc-nav-level-3"><a class="toc-nav-link" href="#1-1-3-RDB%E6%96%87%E4%BB%B6%E7%BB%93%E6%9E%84"><span class="toc-nav-text">1.1.3 RDB文件结构</span></a></li><li class="toc-nav-item toc-nav-level-3"><a class="toc-nav-link" href="#1-1-4-RDB%E6%96%87%E4%BB%B6%E8%BD%BD%E5%85%A5%E6%81%A2%E5%A4%8D"><span class="toc-nav-text">1.1.4 RDB文件载入恢复</span></a></li><li class="toc-nav-item toc-nav-level-3"><a class="toc-nav-link" href="#1-1-5-RDB%E6%8C%81%E4%B9%85%E5%8C%96%E4%BC%98%E7%BC%BA%E7%82%B9"><span class="toc-nav-text">1.1.5 RDB持久化优缺点</span></a></li></ol></li><li class="toc-nav-item toc-nav-level-2"><a class="toc-nav-link" href="#1-2-AOF%E6%8C%81%E4%B9%85%E5%8C%96"><span class="toc-nav-text">1.2 AOF持久化</span></a><ol class="toc-nav-child"><li class="toc-nav-item toc-nav-level-3"><a class="toc-nav-link" href="#1-2-1-AOF%E7%AE%80%E8%BF%B0"><span class="toc-nav-text">1.2.1 AOF简述</span></a></li><li class="toc-nav-item toc-nav-level-3"><a class="toc-nav-link" href="#1-2-2-AOF%E9%85%8D%E7%BD%AE"><span class="toc-nav-text">1.2.2 AOF配置</span></a></li><li class="toc-nav-item toc-nav-level-3"><a class="toc-nav-link" href="#1-2-3-AOF%E6%8C%81%E4%B9%85%E5%8C%96%E4%BC%98%E7%BC%BA%E7%82%B9"><span class="toc-nav-text">1.2.3 AOF持久化优缺点</span></a></li></ol></li><li class="toc-nav-item toc-nav-level-2"><a class="toc-nav-link" href="#1-3-RDB-AOF%E6%B7%B7%E5%90%88%E6%8C%81%E4%B9%85%E5%8C%96"><span class="toc-nav-text">1.3 RDB-AOF混合持久化</span></a><ol class="toc-nav-child"><li class="toc-nav-item toc-nav-level-3"><a class="toc-nav-link" href="#1-3-1-RDB-AOF%E6%B7%B7%E5%90%88%E6%8C%81%E4%B9%85%E5%8C%96%E7%AE%80%E8%BF%B0"><span class="toc-nav-text">1.3.1 RDB-AOF混合持久化简述</span></a></li><li class="toc-nav-item toc-nav-level-3"><a class="toc-nav-link" href="#1-3-2-RDB%E5%92%8CAOF%E5%90%8C%E6%97%B6%E5%BC%80%E5%90%AF%E9%97%AE%E9%A2%98"><span class="toc-nav-text">1.3.2 RDB和AOF同时开启问题</span></a></li></ol></li></ol></li><li class="toc-nav-item toc-nav-level-1"><a class="toc-nav-link" href="#2-%E5%8F%82%E8%80%83%E8%B5%84%E6%96%99"><span class="toc-nav-text">2. 参考资料</span></a></li></ol>
    
  </div>
</aside>
  
  <!-- Catalog END -->
</main>

<script>
  (function () {
    var url = 'http://example.com/2020/04/17/Redis持久化机制/';
    var banner = ''
    if (banner !== '' && banner !== 'undefined' && banner !== 'null') {
      $('#article-banner').css({
        'background-image': 'url(' + banner + ')'
      })
    } else {
      $('#article-banner').geopattern(url)
    }
    $('.header').removeClass('fixed-header')

    // error image
    $(".markdown-content img").on('error', function() {
      $(this).attr('src', '/css/images/error_icon.png')
      $(this).css({
        'cursor': 'default'
      })
    })

    // zoom image
    $(".markdown-content img").on('click', function() {
      var src = $(this).attr('src')
      if (src !== '/css/images/error_icon.png') {
        var imageW = $(this).width()
        var imageH = $(this).height()

        var zoom = ($(window).width() * 0.95 / imageW).toFixed(2)
        zoom = zoom < 1 ? 1 : zoom
        zoom = zoom > 2 ? 2 : zoom
        var transY = (($(window).height() - imageH) / 2).toFixed(2)

        $('body').append('<div class="image-view-wrap"><div class="image-view-inner"><img src="'+ src +'" /></div></div>')
        $('.image-view-wrap').addClass('wrap-active')
        $('.image-view-wrap img').css({
          'width': `${imageW}`,
          'transform': `translate3d(0, ${transY}px, 0) scale3d(${zoom}, ${zoom}, 1)`
        })
        $('html').css('overflow', 'hidden')

        $('.image-view-wrap').on('click', function() {
          $(this).remove()
          $('html').attr('style', '')
        })
      }
    })
  })();
</script>


  <script>
    var qr = new QRious({
      element: document.getElementById('share-qrcode'),
      value: document.location.href
    });
  </script>






    <div class="scroll-top">
  <span class="arrow-icon"></span>
</div>
    <footer class="app-footer">
  <p class="copyright">
    &copy; 2024 | Proudly powered by <a href="https://hexo.io" target="_blank">Hexo</a>
    <br>
    Theme by <a target="_blank" rel="noopener" href="https://github.com/ltyeamin">tong.li</a>
  </p>
</footer>

<script>
  function async(u, c) {
    var d = document, t = 'script',
      o = d.createElement(t),
      s = d.getElementsByTagName(t)[0];
    o.src = u;
    if (c) { o.addEventListener('load', function (e) { c(null, e); }, false); }
    s.parentNode.insertBefore(o, s);
  }
</script>
<script>
  async("https://cdn.staticfile.org/fastclick/1.0.6/fastclick.min.js", function(){
    FastClick.attach(document.body);
  })
</script>

<script>
  var hasLine = 'true';
  async("https://cdn.staticfile.org/highlight.js/9.12.0/highlight.min.js", function(){
    $('figure pre').each(function(i, block) {
      var figure = $(this).parents('figure');
      if (hasLine === 'false') {
        figure.find('.gutter').hide();
      }
      hljs.configure({useBR: true});
      var lang = figure.attr('class').split(' ')[1] || 'code';
      var codeHtml = $(this).html();
      var codeTag = document.createElement('code');
      codeTag.className = lang;
      codeTag.innerHTML = codeHtml;
      $(this).attr('class', '').empty().html(codeTag);
      figure.attr('data-lang', lang.toUpperCase());
      hljs.highlightBlock(block);
    });
  })
</script>
<!-- Baidu Tongji -->



<script src='https://cdn.staticfile.org/mermaid/8.11.2/mermaid.min.js'></script>



<script src="/js/script.js"></script>


  </body>
</html>